package com.hmall.gateway.routes;

import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

@Slf4j
@Component
@RequiredArgsConstructor
public class DynaminRouteLoader {

    private final NacosConfigManager nacosConfigManager;

    private final RouteDefinitionWriter routeDefinitionWriter;

    private final String dataId = "dynamic-route.json";
    private final String group = "DEFAULT_GROUP";

    private Set<String> routeIds = new HashSet<>();

    @PostConstruct
    public void initRouteConfigListener() throws NacosException {
        //1.项目启动，先拉取一次配置，并添加配置监听器
        String configInfo = nacosConfigManager.getConfigService()
                .getConfigAndSignListener(dataId,
                        group,
                        5000,
                        new Listener() {
                            @Override
                            public Executor getExecutor() {
                                return null;
                            }

                            @Override
                            public void receiveConfigInfo(String configInfo) {
                                //2.监听到配置变化，需要去更新路由
                                updateRouteConfig(configInfo);
                            }
                });
        //3.第一次读取到配置，也需要更新到路由表
        updateRouteConfig(configInfo);
    }

    public void updateRouteConfig(String configInfo){
        log.debug("监听到路由变更信息" + configInfo);
        //TODO 4.更新路由表
        //1.解析配置信息，转换成RouteDefinition对象

        List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class);

        //2.删除旧路由表
        for (String routeId : routeIds) {
            routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();
        }
        routeIds.clear();
        //3添加新路由表
        for (RouteDefinition routeDefinition : routeDefinitions) {
            //2更新路由表
            routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
            //记录路由id
            routeIds.add(routeDefinition.getId());
        }
    }
}
